"""
GUI界面模块

提供基于tkinter的图形用户界面，用于视频标注和关键词搜索
"""

import tkinter as tk
from tkinter import scrolledtext, messagebox
from threading import Thread
from typing import List
from video_annotation_middleware import VideoAnnotationMiddleware, CMatchVideo


class VideoAnnotationGUI:
    """
    视频标注系统图形用户界面主类
    
    提供批量视频处理和关键词搜索的用户界面
    """
    
    def __init__(self):
        """
        初始化GUI界面
        
        创建tkinter根窗口和VideoAnnotationMiddleware实例
        """
        # 初始化VideoAnnotationMiddleware实例
        self.middleware = VideoAnnotationMiddleware()
        
        # 初始化tkinter根窗口
        self.root = tk.Tk()
        self.root.title("IOT视频标注系统")
        self.root.geometry("800x600")
        
        # 分页相关变量
        self.search_results = []  # 存储搜索结果
        self.current_page = 0  # 当前页码（从0开始）
        self.current_keyword = ""  # 当前搜索关键词
        
        # 设置UI组件
        self._setup_ui()
    
    def _setup_ui(self):
        """
        构建UI界面组件
        
        创建所有界面元素：按钮、输入框、显示区域等
        """
        # 设置主框架的内边距
        main_frame = tk.Frame(self.root, padx=20, pady=20)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 标题标签
        title_label = tk.Label(
            main_frame, 
            text="IOT视频标注系统", 
            font=("Arial", 16, "bold")
        )
        title_label.pack(pady=(0, 20))
        
        # 批量处理按钮
        self.process_button = tk.Button(
            main_frame,
            text="开始识别所有视频",
            command=self.on_process_all_videos,
            font=("Arial", 12),
            bg="#4CAF50",
            fg="white",
            padx=20,
            pady=10,
            cursor="hand2"
        )
        self.process_button.pack(pady=(0, 10))
        
        # 进度信息显示区域
        progress_label = tk.Label(
            main_frame,
            text="进度信息：",
            font=("Arial", 10, "bold"),
            anchor="w"
        )
        progress_label.pack(fill=tk.X, pady=(10, 5))
        
        self.progress_text = scrolledtext.ScrolledText(
            main_frame,
            height=8,
            font=("Consolas", 9),
            wrap=tk.WORD,
            state=tk.DISABLED
        )
        self.progress_text.pack(fill=tk.BOTH, expand=False, pady=(0, 20))
        
        # 关键词搜索区域
        search_frame = tk.Frame(main_frame)
        search_frame.pack(fill=tk.X, pady=(10, 10))
        
        search_label = tk.Label(
            search_frame,
            text="关键词搜索：",
            font=("Arial", 10, "bold")
        )
        search_label.pack(side=tk.LEFT, padx=(0, 10))
        
        # 关键词输入框
        self.keyword_entry = tk.Entry(
            search_frame,
            font=("Arial", 11),
            width=30
        )
        self.keyword_entry.pack(side=tk.LEFT, padx=(0, 10))
        
        # 搜索按钮
        self.search_button = tk.Button(
            search_frame,
            text="搜索",
            command=self.on_search_keyword,
            font=("Arial", 10),
            bg="#2196F3",
            fg="white",
            padx=15,
            pady=5,
            cursor="hand2"
        )
        self.search_button.pack(side=tk.LEFT)
        
        # 搜索结果显示区域
        results_label = tk.Label(
            main_frame,
            text="搜索结果：",
            font=("Arial", 10, "bold"),
            anchor="w"
        )
        results_label.pack(fill=tk.X, pady=(10, 5))
        
        self.results_text = scrolledtext.ScrolledText(
            main_frame,
            height=12,
            font=("Consolas", 9),
            wrap=tk.WORD,
            state=tk.DISABLED
        )
        self.results_text.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        # 配置文本标签用于高亮关键词
        self.results_text.tag_config("keyword", background="yellow", foreground="red", font=("Consolas", 9, "bold"))
        
        # 分页控制区域
        pagination_frame = tk.Frame(main_frame)
        pagination_frame.pack(fill=tk.X, pady=(5, 0))
        
        # 上一页按钮
        self.prev_button = tk.Button(
            pagination_frame,
            text="◀ 上一页",
            command=self.on_prev_page,
            font=("Arial", 10),
            bg="#9E9E9E",
            fg="white",
            padx=15,
            pady=5,
            cursor="hand2",
            state=tk.DISABLED
        )
        self.prev_button.pack(side=tk.LEFT, padx=(0, 10))
        
        # 页码显示标签
        self.page_label = tk.Label(
            pagination_frame,
            text="",
            font=("Arial", 10)
        )
        self.page_label.pack(side=tk.LEFT, padx=10)
        
        # 下一页按钮
        self.next_button = tk.Button(
            pagination_frame,
            text="下一页 ▶",
            command=self.on_next_page,
            font=("Arial", 10),
            bg="#9E9E9E",
            fg="white",
            padx=15,
            pady=5,
            cursor="hand2",
            state=tk.DISABLED
        )
        self.next_button.pack(side=tk.LEFT)
    
    def on_process_all_videos(self):
        """
        处理"开始识别所有视频"按钮点击事件
        
        在后台线程中执行批量视频处理
        """
        # 禁用按钮防止重复点击
        self.process_button.config(state=tk.DISABLED)
        
        # 清空进度显示区域
        self.progress_text.config(state=tk.NORMAL)
        self.progress_text.delete(1.0, tk.END)
        self.progress_text.config(state=tk.DISABLED)
        
        # 实现进度回调函数，更新UI进度显示
        def progress_callback(current_video, total_videos, video_name):
            progress_msg = f"正在处理 ({current_video}/{total_videos}): {video_name}"
            self.update_progress(progress_msg)
        
        # 在后台线程中调用middleware.processVideosFromPath
        def process_task():
            try:
                # 首先加载模型
                self.update_progress("正在加载YOLO模型...")
                self.middleware.loadModel()
                self.update_progress("模型加载完成\n")
                
                # 开始批量处理
                self.update_progress("开始批量处理视频...\n")
                result = self.middleware.processVideosFromPath(callback=progress_callback)
                
                # 处理完成后显示统计信息
                self.update_progress("\n" + "="*50)
                self.update_progress("处理完成！")
                self.update_progress(f"总视频数: {result['total']}")
                self.update_progress(f"成功处理: {result['success']}")
                self.update_progress(f"处理失败: {len(result['failed'])}")
                
                if result['failed']:
                    self.update_progress("\n失败的视频:")
                    for failed_video in result['failed']:
                        self.update_progress(f"  - {failed_video}")
                
                self.update_progress("="*50)
                
                # 显示成功消息框
                self.root.after(0, lambda: messagebox.showinfo(
                    "处理完成", 
                    f"成功处理 {result['success']}/{result['total']} 个视频"
                ))
                
            except Exception as e:
                error_msg = f"处理视频时出错: {str(e)}"
                self.update_progress(f"\n错误: {error_msg}")
                self.root.after(0, lambda: messagebox.showerror("错误", error_msg))
            
            finally:
                # 重新启用按钮
                self.root.after(0, lambda: self.process_button.config(state=tk.NORMAL))
        
        # 启动后台线程
        thread = Thread(target=process_task, daemon=True)
        thread.start()
    
    def on_search_keyword(self):
        """
        处理搜索按钮点击事件
        
        执行关键词搜索并显示结果
        """
        # 获取输入框中的关键词
        keyword = self.keyword_entry.get().strip()
        
        # 验证关键词不为空
        if not keyword:
            messagebox.showwarning("输入错误", "请输入搜索关键词")
            return
        
        # 禁用搜索按钮防止重复点击
        self.search_button.config(state=tk.DISABLED)
        
        # 在后台线程中执行搜索
        def search_task():
            try:
                # 调用middleware.searchKeyword方法
                results = self.middleware.searchKeyword(keyword)
                
                # 保存搜索结果和关键词
                self.search_results = results
                self.current_keyword = keyword
                self.current_page = 0
                
                # 调用display_search_results显示结果
                self.display_search_results()
                
            except Exception as e:
                error_msg = f"搜索时出错: {str(e)}"
                self.root.after(0, lambda: messagebox.showerror("搜索错误", error_msg))
            
            finally:
                # 重新启用搜索按钮
                self.root.after(0, lambda: self.search_button.config(state=tk.NORMAL))
        
        # 启动后台线程
        thread = Thread(target=search_task, daemon=True)
        thread.start()
    
    def on_prev_page(self):
        """
        处理上一页按钮点击事件
        """
        if self.current_page > 0:
            self.current_page -= 1
            self.display_search_results()
    
    def on_next_page(self):
        """
        处理下一页按钮点击事件
        """
        if self.current_page < len(self.search_results) - 1:
            self.current_page += 1
            self.display_search_results()
    
    def update_progress(self, message: str):
        """
        更新进度显示区域
        
        参数:
            message: 要显示的进度信息
        """
        # 确保UI更新在主线程中执行（使用root.after）
        def _update():
            self.progress_text.config(state=tk.NORMAL)
            self.progress_text.insert(tk.END, message + "\n")
            self.progress_text.see(tk.END)  # 自动滚动到最新内容
            self.progress_text.config(state=tk.DISABLED)
        
        self.root.after(0, _update)
    
    def display_search_results(self):
        """
        显示搜索结果（分页显示）
        """
        # 确保UI更新在主线程中执行（使用root.after）
        def _display():
            self.results_text.config(state=tk.NORMAL)
            self.results_text.delete(1.0, tk.END)  # 清空之前的结果
            
            if not self.search_results:
                self.results_text.insert(tk.END, "未找到匹配的结果\n")
                self.page_label.config(text="")
                self.prev_button.config(state=tk.DISABLED)
                self.next_button.config(state=tk.DISABLED)
            else:
                # 获取当前页的结果
                match = self.search_results[self.current_page]
                total_pages = len(self.search_results)
                
                # 更新页码显示
                self.page_label.config(text=f"第 {self.current_page + 1} / {total_pages} 个视频")
                
                # 更新翻页按钮状态
                self.prev_button.config(state=tk.NORMAL if self.current_page > 0 else tk.DISABLED)
                self.next_button.config(state=tk.NORMAL if self.current_page < total_pages - 1 else tk.DISABLED)
                
                # 显示视频信息
                self.results_text.insert(tk.END, f"视频: {match.m_videoName}\n")
                self.results_text.insert(tk.END, f"路径: {match.m_videoPath}\n")
                self.results_text.insert(tk.END, f"结果文件: {match.m_resultFile}\n")
                self.results_text.insert(tk.END, f"匹配次数: {match.m_matchCnt}\n")
                self.results_text.insert(tk.END, "="*70 + "\n\n")
                
                # 读取完整的结果文件以获取上下文
                try:
                    from pathlib import Path
                    result_file_path = Path(self.middleware.m_resultsDir) / match.m_resultFile
                    with open(result_file_path, 'r', encoding='utf-8') as f:
                        all_lines = f.readlines()
                    
                    # 获取所有匹配行的行号
                    matched_line_numbers = [line_info['line_number'] for line_info in match.m_matchedLines]
                    
                    # 合并连续的匹配行
                    line_groups = self._merge_consecutive_lines(matched_line_numbers)
                    
                    # 显示每组匹配行及其上下文
                    for group in line_groups:
                        start_line = group[0]
                        end_line = group[-1]
                        
                        # 确定显示范围（包括前一行和后一行）
                        display_start = max(1, start_line - 1)
                        display_end = min(len(all_lines), end_line + 1)
                        
                        # 显示上下文行
                        for line_num in range(display_start, display_end + 1):
                            line_content = all_lines[line_num - 1].rstrip()
                            
                            # 判断是否为匹配行
                            is_matched = line_num in matched_line_numbers
                            
                            if is_matched:
                                # 匹配行：高亮显示关键词
                                prefix = f"  ▶ 第{line_num}行: "
                                self.results_text.insert(tk.END, prefix)
                                self._insert_with_highlight(line_content, self.current_keyword)
                                self.results_text.insert(tk.END, "\n")
                            else:
                                # 上下文行：普通显示
                                self.results_text.insert(tk.END, f"    第{line_num}行: {line_content}\n")
                        
                        self.results_text.insert(tk.END, "\n")
                    
                except Exception as e:
                    self.results_text.insert(tk.END, f"\n读取结果文件时出错: {str(e)}\n")
            
            self.results_text.config(state=tk.DISABLED)
        
        self.root.after(0, _display)
    
    def _merge_consecutive_lines(self, line_numbers: List[int]) -> List[List[int]]:
        """
        合并连续的行号
        
        参数:
            line_numbers: 行号列表
        
        返回值:
            List[List[int]]: 合并后的行号组列表
        """
        if not line_numbers:
            return []
        
        # 排序行号
        sorted_lines = sorted(line_numbers)
        
        groups = []
        current_group = [sorted_lines[0]]
        
        for i in range(1, len(sorted_lines)):
            # 如果当前行号与前一个行号连续，加入当前组
            if sorted_lines[i] == sorted_lines[i-1] + 1:
                current_group.append(sorted_lines[i])
            else:
                # 否则，开始新的组
                groups.append(current_group)
                current_group = [sorted_lines[i]]
        
        # 添加最后一组
        groups.append(current_group)
        
        return groups
    
    def _insert_with_highlight(self, text: str, keyword: str):
        """
        插入文本并高亮显示关键词
        
        参数:
            text: 要插入的文本
            keyword: 要高亮的关键词
        """
        keyword_lower = keyword.lower()
        text_lower = text.lower()
        
        start_pos = 0
        while True:
            # 查找关键词位置（不区分大小写）
            pos = text_lower.find(keyword_lower, start_pos)
            
            if pos == -1:
                # 没有找到更多关键词，插入剩余文本
                self.results_text.insert(tk.END, text[start_pos:])
                break
            
            # 插入关键词前的文本
            self.results_text.insert(tk.END, text[start_pos:pos])
            
            # 插入高亮的关键词
            self.results_text.insert(tk.END, text[pos:pos+len(keyword)], "keyword")
            
            # 更新起始位置
            start_pos = pos + len(keyword)
    
    def run(self):
        """
        启动GUI主循环
        """
        self.root.mainloop()


if __name__ == "__main__":
    """
    主程序入口
    
    创建VideoAnnotationGUI实例并启动应用程序
    捕获并显示启动过程中的任何错误
    """
    try:
        # 创建VideoAnnotationGUI实例
        app = VideoAnnotationGUI()
        # 调用run方法启动GUI主循环
        app.run()
    except Exception as e:
        # 捕获并显示启动错误
        error_message = f"启动GUI时出错: {str(e)}"
        print(error_message)
        
        # 尝试显示错误对话框（如果tkinter可用）
        try:
            root = tk.Tk()
            root.withdraw()  # 隐藏主窗口
            messagebox.showerror("启动错误", f"无法启动应用程序:\n\n{str(e)}")
            root.destroy()
        except:
            # 如果无法显示对话框，只打印到控制台
            print("无法显示错误对话框，请查看控制台输出")
